#include "AT91SAM9260.h"
#include "test.h"
#include "bits.h"
#include "adc.h"

#define		TEST_OK				0
#define		TEST_VCC_A		1
#define		TEST_VCC_B		2
#define		TEST_VCC_C		3
#define		TEST_GND_A		4
#define		TEST_GND_B		5
#define		TEST_GND_C		6
#define		TEST_PIN_A		7
#define		TEST_PIN_B		8
#define		TEST_PIN_C		9
#define		TEST_EXT_VCC	10
#define		TEST_EXT_GND	11
#define		TEST_EXT_PIN	12
#define		TEST_ADC			13

AT91PS_PIO      t_pPioA     = AT91C_BASE_PIOA;
AT91PS_PIO      t_pPioB     = AT91C_BASE_PIOB;
AT91PS_PIO      t_pPioC     = AT91C_BASE_PIOC;
AT91PS_SYS      t_pSys      = AT91C_BASE_SYS;
AT91PS_PMC      t_pPMC      = AT91C_BASE_PMC;


unsigned char l=0;
static unsigned char test_ok;

const unsigned int mask_port_a  = 0x00000000;
const unsigned int mask_port_b  = 0xDFFF0F3F&(~BIT23);    // pullup PB23
const unsigned int mask_port_c  = 0x000087D0;
const unsigned int mask_uext_a  = 0x01800000;
const unsigned int mask_uext_b  = 0x0000030F&(~BIT2);     // pullup PB2

//it's a simple delay
void DelayS (unsigned long a) { while (--a!=0); }

// stop if error
void Stop(unsigned char test_state);

extern void AT91F_DBGU_Printk(	char *buffer);
extern void AT91F_DBGU_Init(void);
//extern int AT91F_US_GetChar (	const AT91PS_USART pUSART);
int AT91F_US_GetChar (
	const AT91PS_USART pUSART)
{
    return((pUSART->US_RHR) & 0x1FF);
}

inline unsigned int AT91F_US_RxReady (
	AT91PS_USART pUSART )     // \arg pointer to a USART controller
{
    return (pUSART->US_CSR & AT91C_US_RXRDY);
}

void write_str_USART0( char* str)
{
	//return;
	AT91F_DBGU_Printk(str);
}

unsigned char read_char_USART0(void)
{
	return (unsigned char)AT91F_US_GetChar((AT91PS_USART)AT91C_BASE_DBGU);
}

unsigned char DBGU_IsRxRdy(void)
{
	return (unsigned char)AT91F_US_RxReady((AT91PS_USART)AT91C_BASE_DBGU);
}

void TestADC(void)
{
	unsigned int val;
	InitADC();

  val = GetAdcChanel(ADC_CHN_1);
  if((val<300)||(val>380)) {
    // error
    val = 0;
  }
  val = GetAdcChanel(ADC_CHN_2);
  if((val<640)||(val>720)) {
    // error
    val=0;
  }
}

unsigned char  TestBoard(void) {

  //enable the clock of the PIO
  t_pPMC->PMC_PCER = 1 << AT91C_ID_PIOA;
  //enable the clock of the PIO
  t_pPMC->PMC_PCER = 1 << AT91C_ID_PIOB;
  //enable the clock of the PIO
  t_pPMC->PMC_PCER = 1 << AT91C_ID_PIOC;
	t_pPMC->PMC_PCER = 1 << AT91C_ID_PIOC;
	


  write_str_USART0("\n\r\n\r\n\r\0");
  write_str_USART0("\n\r**** TEST EXTENSION BEGIN*****\n\r\0");	
  write_str_USART0("\n\rPlease put EXT and press any key to continue\0");
	//while( ! read_char_USART0());
	while ( ! DBGU_IsRxRdy());
	read_char_USART0();
	test_ok = 1;

  // just simple delay
  DelayS(500000);

  // GPIO init
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioC->PIO_ODR    = 0x0000ffff;   // All as input
  t_pSys->PIOA_PPUDR  = 0xffffffff;   // Disable Pull-up resistor
  t_pSys->PIOB_PPUDR  = 0xffffffff;   // Disable Pull-up resistor
  t_pSys->PIOC_PPUDR  = 0xffffffff;   // Disable Pull-up resistor
  t_pPioA->PIO_PPUDR  = 0xffffffff;   // Disable Pull-up resistor
  t_pPioB->PIO_PPUDR  = 0xffffffff;   // Disable Pull-up resistor
  t_pPioC->PIO_PPUDR  = 0xffffffff;   // Disable Pull-up resistor


  // all as GPIO
  t_pPioA->PIO_PER = 0xffffffff;    //Disables the PIO from controlling the corresponding pin (enables peripheral control of the pin).
  t_pPioA->PIO_ASR = 0;             //Assigns the I/O line to the peripheral B function.
  t_pPioA->PIO_BSR = 0;
  t_pPioB->PIO_PER = 0xffffffff;    //Disables the PIO from controlling the corresponding pin (enables peripheral control of the pin).
  t_pPioB->PIO_ASR = 0;             //Assigns the I/O line to the peripheral B function.
  t_pPioB->PIO_BSR = 0;
  t_pPioC->PIO_PER = 0x0000ffff;    //Disables the PIO from controlling the corresponding pin (enables peripheral control of the pin).
  t_pPioC->PIO_ASR = 0;             //Assigns the I/O line to the peripheral B function.
  t_pPioC->PIO_BSR = 0;



  //===========================================================

  ////// TEST EXT ////////
  // pull up is PB23

  //// Test for VCC /////---------------------------------------

  // all as input
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioC->PIO_ODR    = 0x0000ffff;   // All as input

  // just simple delay
  DelayS(1000);

  // pull up
  t_pPioB->PIO_CODR   = BIT23; // low
  t_pPioB->PIO_OER    = BIT23; // output
  t_pPioB->PIO_SODR   = BIT23; // low
  t_pPioB->PIO_CODR   = BIT23; // low
  t_pPioB->PIO_SODR   = BIT23; // low
  t_pPioB->PIO_CODR   = BIT23; // low

  // just simple delay
  DelayS(1000);

  // check for high on port A
  if((t_pPioA->PIO_PDSR&mask_port_a) != 0x0) {
    //state_ext_vcc_porta = 1;
    Stop(TEST_VCC_A);
  }

  // check for high on port B
  if((t_pPioB->PIO_PDSR&mask_port_b) != 0x0) {
    //state_ext_vcc_portb = 1;
    Stop(TEST_VCC_B);
  }

  // check for high on port C
  if((t_pPioC->PIO_PDSR&mask_port_c) != 0x0) {
    //state_ext_vcc_portc = 1;
    Stop(TEST_VCC_C);
  }

  //// End test for VCC /////---------------------------------------

  //// Test for GND /////-----------------------------------

  // all as input
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioC->PIO_ODR    = 0x0000ffff;   // All as input

  // just simple delay
  DelayS(1000);

  // pull up
  t_pPioB->PIO_SODR   = BIT23; // high
  t_pPioB->PIO_OER    = BIT23; // output

  // just simple delay
  DelayS(1000);

  // check for low on port A
  if((t_pPioA->PIO_PDSR|(~mask_port_a)) != 0xFFFFFFFF) {
    //state_ext_gnd_porta = 1;
    Stop(TEST_GND_A);
  }

  // check for low on port b
  if((t_pPioB->PIO_PDSR|(~mask_port_b)) != 0xFFFFFFFF) {
    //state_ext_gnd_portb = 1;
    Stop(TEST_GND_B);
  }

  // check for low on port b
  if((t_pPioC->PIO_PDSR|(~mask_port_c)) != 0xFFFFFFFF) {
    //state_ext_gnd_portc = 1;
    Stop(TEST_GND_C);
  }

  //// End test for GND /////-----------------------------------

  ///// Running zero ///////-----------------------------------

  ///// for PortA

  // all as input
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioC->PIO_ODR    = 0x0000ffff;   // All as input

  // just simple delay
  DelayS(1000);

  // pull up
  t_pPioB->PIO_SODR   = BIT23; // high
  t_pPioB->PIO_OER    = BIT23; // output

  // just simple delay
  DelayS(1000);

  // loop for port a
  for(l=0; l<32; l++) {

    // this port is not tested
    if(!((mask_port_a)&(1<<l))) continue;

    t_pPioA->PIO_SODR   = 0xffffffff;
    t_pPioA->PIO_CODR   = (1<<l);

    t_pPioA->PIO_ODR    = 0xffffffff;
    t_pPioA->PIO_OER    = (1<<l);

    // just simple delay
    DelayS(1000);

    // check for other zero at port A
    if((t_pPioA->PIO_PDSR|(~mask_port_a)) != ((0xFFFFFFFF)&(~(1<<l)))) {
      //state_ext_pin_porta = l;
      Stop(TEST_PIN_A);
    }

    // check for other zero at port B
    if((t_pPioB->PIO_PDSR|(~mask_port_b)) != ((0xFFFFFFFF))) {
      //state_ext_pin_portb = l;
      Stop(TEST_PIN_B);
    }

    // check for other zero at port C
    if((t_pPioC->PIO_PDSR|(~mask_port_c)) != ((0xFFFFFFFF))) {
      //state_ext_pin_portc = l;
      Stop(TEST_PIN_C);
    }
  }


  ///// for PortB

  // all as input
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioC->PIO_ODR    = 0x0000ffff;   // All as input

  // just simple delay
  DelayS(1000);

  // pull up
  t_pPioB->PIO_SODR   = BIT23; // high
  t_pPioB->PIO_OER    = BIT23; // output

  // just simple delay
  DelayS(1000);

  // loop for port b
  for(l=0; l<32; l++) {

    // this port is not tested
    if(!((mask_port_b)&(1<<l))) continue;

    t_pPioB->PIO_SODR   = 0xffffffff;
    t_pPioB->PIO_CODR   = (1<<l);

    t_pPioB->PIO_ODR    = 0xffffffff;
    t_pPioB->PIO_OER    = (1<<l)|BIT23;

    // just simple delay
    DelayS(1000);

    // check for other zero at port A
    if((t_pPioA->PIO_PDSR|(~mask_port_a)) != ((0xFFFFFFFF))) {
      //state_ext_pin_porta = l;
      Stop(TEST_PIN_A);
    }

    // check for other zero at port B
    if((t_pPioB->PIO_PDSR|(~mask_port_b)) != ((0xFFFFFFFF)&(~(1<<l)))) {
      //state_ext_pin_portb = l;
      Stop(TEST_PIN_B);
    }

    // check for other zero at port C
    if((t_pPioC->PIO_PDSR|(~mask_port_c)) != ((0xFFFFFFFF))) {
      //state_ext_pin_portc = l;
      Stop(TEST_PIN_C);
    }
  }


  ///// for PortC

  // all as input
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioC->PIO_ODR    = 0x0000ffff;   // All as input

  // just simple delay
  DelayS(1000);

  // pull up
  t_pPioB->PIO_SODR   = BIT23; // high
  t_pPioB->PIO_OER    = BIT23; // output

  // just simple delay
  DelayS(1000);

  // loop for port c
  for(l=0; l<32; l++) {

    // this port is not tested
    if(!((mask_port_c)&(1<<l))) continue;

    t_pPioC->PIO_SODR   = 0xffffffff;
    t_pPioC->PIO_CODR   = (1<<l);

    t_pPioC->PIO_ODR    = 0xffffffff;
    t_pPioC->PIO_OER    = (1<<l);

    // just simple delay
    DelayS(1000);

    // check for other zero at port A
    if((t_pPioA->PIO_PDSR|(~mask_port_a)) != ((0xFFFFFFFF))) {
      //state_ext_pin_porta = l;
      Stop(TEST_PIN_A);
    }

    // check for other zero at port B
    if((t_pPioB->PIO_PDSR|(~mask_port_b)) != ((0xFFFFFFFF))) {
      //state_ext_pin_portb = l;
      Stop(TEST_PIN_B);
    }

    // check for other zero at port C
    if((t_pPioC->PIO_PDSR|(~mask_port_c)) != ((0xFFFFFFFF)&(~(1<<l)))) {
      //state_ext_pin_portc = l;
      Stop(TEST_PIN_C);
    }
  }

  ///// End Running zero ///////-----------------------------------

	AT91F_DBGU_Init();
	write_str_USART0("\n\r**** TEST EXT OK *****\n\r\0");	
	write_str_USART0("\n\r\n\r\n\r\0");
  write_str_USART0("\n\r**** TEST UEXT BEGIN*****\n\r\0");	
  write_str_USART0("\n\rPlease remove EXT, put UEXT and press any key to continue\0");
	//while( ! read_char_USART0());
	while ( ! DBGU_IsRxRdy());
	read_char_USART0();
	
	
  ////// TEST UEXT ////////
  // pull up is PA22

  //// Test for VCC /////---------------------------------------

  // all as input
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input

  // just simple delay
  DelayS(1000);

  // pull up
  t_pPioB->PIO_CODR   = BIT2; // low
  t_pPioB->PIO_OER    = BIT2; // output


  // just simple delay
  DelayS(1000);

  // check for high on port A
  if((t_pPioA->PIO_PDSR&mask_uext_a) != 0x0) {
    //state_ext_vcc_uext = 1;
    Stop(TEST_EXT_VCC);
  }

  // check for high on port A
  if((t_pPioB->PIO_PDSR&mask_uext_b) != 0x0) {
    //state_ext_vcc_uext = 1;
    Stop(TEST_EXT_VCC);
  }


  //// End test for VCC /////---------------------------------------

  //// Test for GND /////-----------------------------------

  // all as input
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input

  // just simple delay
  DelayS(1000);

  // pull up
  t_pPioB->PIO_SODR   = BIT2; // high
  t_pPioB->PIO_OER    = BIT2; // output

  // just simple delay
  DelayS(1000);

  // check for low on port A
  if((t_pPioA->PIO_PDSR|(~mask_uext_a)) != 0xFFFFFFFF) {
    //state_ext_gnd_uext = 1;
    Stop(TEST_EXT_GND);
  }

  // check for low on port A
  if((t_pPioB->PIO_PDSR|(~mask_uext_b)) != 0xFFFFFFFF) {
    //state_ext_gnd_uext = 1;
    Stop(TEST_EXT_GND);
  }
  //// End test for GND /////-----------------------------------

  ///// Running zero ///////-----------------------------------

  ///// for PortA

  // all as input
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input

  // just simple delay
  DelayS(1000);

  // pull up
  t_pPioB->PIO_SODR   = BIT2; // high
  t_pPioB->PIO_OER    = BIT2; // output

  // just simple delay
  DelayS(1000);

  // loop for port a
  for(l=0; l<32; l++) {

    // this port is not tested
    if(!((mask_uext_a)&(1<<l))) continue;

    t_pPioA->PIO_SODR   = 0xffffffff;
    t_pPioA->PIO_CODR   = (1<<l);

    t_pPioA->PIO_ODR    = 0xffffffff;
    t_pPioA->PIO_OER    = (1<<l);

    // just simple delay
    DelayS(1000);

    // check for other zero at port A
    if((t_pPioA->PIO_PDSR|(~mask_uext_a)) != ((0xFFFFFFFF)&(~(1<<l)))) {
      //state_ext_pin_uext = l;
      Stop(TEST_EXT_PIN);
    }
    // check for other zero at port B
    if((t_pPioB->PIO_PDSR|(~mask_uext_b)) != ((0xFFFFFFFF))) {
      //state_ext_pin_uext = l;
      Stop(TEST_EXT_PIN);
    }
  }

  // all as input
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input

  // loop for port b
  for(l=0; l<32; l++) {

    // this port is not tested
    if(!((mask_uext_b)&(1<<l))) continue;

    t_pPioB->PIO_SODR   = 0xffffffff;
    t_pPioB->PIO_CODR   = (1<<l);

    t_pPioB->PIO_ODR    = 0xffffffff;
    t_pPioB->PIO_OER    = (1<<l) | BIT2;

    // just simple delay
    DelayS(1000);

    // check for other zero at port A
    if((t_pPioA->PIO_PDSR|(~mask_uext_a)) != ((0xFFFFFFFF))) {
      //state_ext_pin_uext = l;
      Stop(TEST_EXT_PIN);
    }
    // check for other zero at port B
    if((t_pPioB->PIO_PDSR|(~mask_uext_b)) != ((0xFFFFFFFF)&(~(1<<l)))) {
      //state_ext_pin_uext = l;
      Stop(TEST_EXT_PIN);
    }
  }

	AT91F_DBGU_Init();
	write_str_USART0("\n\r**** TEST UEXT OK *****\n\r\0");	
	write_str_USART0("\n\r\n\r\n\r\0");
  write_str_USART0("\n\r**** TEST ADC BEGIN*****\n\r\0");	
  write_str_USART0("\n\rPut ANALOG and press any key to continue\0");
	//while( ! read_char_USART0());
	while ( ! DBGU_IsRxRdy());
	read_char_USART0();
	
	InitADC();

  unsigned int val = GetAdcChanel(ADC_CHN_1);
  if((val<300)||(val>380)) {
    Stop(TEST_ADC);
  }
  val = GetAdcChanel(ADC_CHN_2);
  if((val<640)||(val>720)) {
    Stop(TEST_ADC);
  }
	

  write_str_USART0("\n\r**** ALL TEST EXTENSION OK*****\n\r\0");
  write_str_USART0("\n\r**** Test BUT, STAT and UART1 *****\n\r\0");
  write_str_USART0("\n\r\0");
  write_str_USART0("\n\r\0");
	//return TEST_OK;
	
	return test_ok;
	
	

}



void Stop(unsigned char test_state) {

  // GPIO init
  t_pPioA->PIO_ODR    = 0xffffffff;   // All as input
  t_pPioB->PIO_ODR    = 0xffffffff;   // All as input
  t_pSys->PIOA_PPUDR  = 0xffffffff;   // Disable Pull-up resistor
  t_pSys->PIOB_PPUDR  = 0xffffffff;   // Disable Pull-up resistor
	
	AT91F_DBGU_Init();

  // just simple delay
  DelayS(1000);
	
	switch (test_state)
	{
		case TEST_VCC_A:
			write_str_USART0("\n\r Pin to VCC at Port A");
			break;
		case TEST_VCC_B:
			write_str_USART0("\n\r Pin to VCC at Port B");
			break;
		case TEST_VCC_C:
			write_str_USART0("\n\r Pin to VCC at Port C");
			break;
		case TEST_GND_A:
			write_str_USART0("\n\r Pin to GND at Port A");
			break;
		case TEST_GND_B:
			write_str_USART0("\n\r Pin to GND at Port B");
			break;
		case TEST_GND_C:
			write_str_USART0("\n\r Pin to GND at Port C");
			break;
		case TEST_PIN_A:
			write_str_USART0("\n\r Pin short at Port A");
			break;
		case TEST_PIN_B:
			write_str_USART0("\n\r Pin short at Port B");
			break;
		case TEST_PIN_C:
			write_str_USART0("\n\r Pin short at Port C");
			break;
		case TEST_EXT_VCC:
			write_str_USART0("\n\r Pin to VCC at UEXT");
			break;
		case TEST_EXT_GND:
			write_str_USART0("\n\r Pin to GND at UEXT");
			break;
		case TEST_EXT_PIN:
			write_str_USART0("\n\r Pin short at UEXT");
			break;
		case TEST_ADC:
			write_str_USART0("\n\r ADC Error");
			break;

			
	}
	
	test_ok=0;

  //while(1);

}
